package tester

import (
	"fmt"
)

type flow interface {
	run(*tester) string
	stps() []string
}

type nextstep struct {
	stepName string
}

func (n *nextstep) run(t *tester) string {
	return n.stepName
}

func (n *nextstep) stps() []string {
	return []string{n.stepName}
}

// next: nextstep;
// error: nextstep;
func parseNext(b []byte, start int) (int, *nextstep, error) {
	p, stepname, err := readParaValue(b, start)
	if err != nil {
		return p, nil, err
	}

	ns := &nextstep{
		stepName: stepname,
	}

	return p, ns, nil
}

type branch struct {
	c        *cond
	stepName string
}

type brstep struct {
	brs []*branch

	defStepName string
}

func (b *brstep) run(t *tester) string {
	for _, br := range b.brs {
		if br.c.match(t.vars) {
			return br.stepName
		}
	}

	return b.defStepName
}

func (b *brstep) stps() []string {
	ret := []string{b.defStepName}

	for _, br := range b.brs {
		ret = append(ret, br.stepName)
	}

	return ret
}

//	branch {
//	  $varName value: stepname1;    // prefix match
//	  $varName == value: stepname2; // equal match
//	  $varName != value: stepname3; // unequal match
//	  $varName ~ value: stepname4;  // regex match
//	  default: stepname5;
//	}
func parseBranch(b []byte, start int) (int, *brstep, error) {
	brs := &brstep{
		brs: []*branch{},
	}

	var pr tokenResultType
	var token string
	var stepname string
	var err error
	var p int

	last := len(b)

	for {
		if start == last {
			return p, nil, fmt.Errorf("conf end when parse branch step")
		}

		pr, p, token = readToken(b, start)
		switch pr {
		case para_start:
			start = p + 1

			if token == "default" {
				if brs.defStepName != "" {
					return p, nil, fmt.Errorf("has more than one default branch")
				}

				p, stepname, err = readParaValue(b, start)
				if err != nil {
					return p, nil, err
				}

				brs.defStepName = stepname
			} else {
				if token[0] != '$' {
					return p, nil, fmt.Errorf("unexpected para name format in cond expr: %s", token)
				}
				token = token[1:]

				cond, err := parseCond(token)
				if err != nil {
					return p, nil, err
				}

				p, stepname, err = readParaValue(b, start)
				if err != nil {
					return p, nil, err
				}

				br := &branch{
					c:        cond,
					stepName: stepname,
				}

				brs.brs = append(brs.brs, br)
			}

			start = p + 1

		case block_end:
			if token != "" {
				return p, nil, fmt.Errorf("unexpected token type %s when parse branch step", pr)
			}

			if brs.defStepName == "" {
				brs.defStepName = stepErr
			}

			return p, brs, nil

		default:
			return p, nil, fmt.Errorf("unexpected token type %s when parse branch step", pr)
		}
	}

}
